#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#include "ak_config.h"
#include "ak_ini.h"
#include "ak_common.h"
#include "ak_net.h"
#include "ak_cmd_exec.h"

#define BUF_SIZE (100)
#define CONFIG_VALUE_BUF_SIZE		50
#define CONFIG_DUMP_INFO			0

/* default config file */
#define CONFIG_ANYKA_FILE_NAME  	"/etc/jffs2/anyka_cfg.ini"
#define CONFIG_PTZ_UNHIT_NAME  		"/tmp/ak_sys_start_flag"

struct ptz_pos {
	int left;
	int up;
};

struct sys_config {
	void *handle;

	struct sys_user_config *user;		/* title: global */
	struct video_config *video;			/* title: video */
	struct video_record_config *record;	/* title: record */
	struct sys_alarm_config *alarm;		/* title: alarm */
	struct sys_cloud_config *cloud;		/* title: cloud */
	struct sys_onvif_config *onvif;		/* title: onvif */
	struct sys_net_config *net;			/* title: ethernet */
	struct sys_wifi_config *wifi;		/* title: wireless */
	struct camera_disp_config *camera;	/* title: camera */
};

static struct sys_config config = {NULL};
static const char config_version[] = "app_config V2.1.00";

/**
 * ak_config_get_version - get config version
 * return: version string
 */
const char* ak_config_get_version(void)
{
	return config_version;
}

/**
 * day_clock_to_seconds - transfer current day time clock to seconds
 * @clock[IN]: current day time clock
 * return: seconds after transferred
 * notes: clock format: 06:45:20
 */
static time_t day_clock_to_seconds(const char *clock)
{
	int colon_num = 0;
	char *tmp = NULL;
	char *min_tmp = NULL;
	char *sec_tmp = NULL;

	tmp = strchr(clock, ':');
	while(NULL != tmp){
		++colon_num;

    	++tmp;
		tmp = strchr(tmp, ':');
	}
	if(colon_num < 2){
		return 0;
	}

    min_tmp = strchr(clock, ':');
    *min_tmp = 0x00;
    ++min_tmp;
    int hour = atoi(clock);
    if(hour >= 24){
    	hour = 23;
    }

    sec_tmp = strchr(min_tmp, ':');
    *sec_tmp = 0x00;
    ++sec_tmp;
	int min = atoi(min_tmp);
	int sec = atoi(sec_tmp);
	if(min >= 60){
		min = 59;
	}
	if(sec >= 60){
		sec = 59;
	}

	return ((hour*60*60) + (min*60) + sec);
}

/**
 * day_second_to_string - transfer current day time clock to string
 * @clock[OUT]: current day time clock hh:mm:ss
 * @second[IN]: second . since from 00h:00minutes:00second
 * return: void
 * notes: clock format: 06:45:20
 */
static void day_second_to_string(char *clock,time_t second)
{
	memset(clock, 0, 20);
	sprintf(clock,"%2d:%2d:%2d",(int)second/(60*60),(int)(second %(60*60))/60,
		(int) second % 60);
}

/** save_week_config_info: enable appointed weed day
 * @day_index: appointed day index
 * @week[OUT]: week day info
 * return: none
 */
static void enable_week_day(int day_index, int *week)
{
	if(day_index >= DAY_PER_WEEK){
		week[0] = 0x01;
	}else{
		week[day_index] = 0x01;
	}
}

/** enable_week_day: transfer string value to week day value
 * @value: week day string
 * @week[OUT]: week day info
 * return: none
 */
static void save_week_config_info(char *value, int *week)
{
	int i = 0;
	int index = 0;
	int str_len = strlen(value);

	for(i=0; i<str_len; ++i){
		switch(value[i]){
		case '-':
			if(0x00 == i){
				ak_print_normal_ex("week active config INVALID\n");
			}else{
				int start_day = atoi(&value[i-1]);	//we reset start day
				int end_day = atoi(&value[i+1]);

 				if(start_day < 0x01){
					start_day = 0x01;
				}
				if(end_day > 0x07){
					end_day = 0x07;
				}

				/* including end_day, ex: 1-7 is Monday to Sunday */
				for(index=start_day; index<=end_day; ++index){
					enable_week_day(index, week);
				}

				++i;//skip number after '-'
			}
			break;
		case ',':	//just skip ','
			break;
		default:
			/* single week day */
			index = atoi(&value[i]);
			enable_week_day(index, week);
			break;
		}
	}
}

/** get_week_config_info_str: transfer week day value to string
 * @value[OUT]: week day string
 * @week[IN]: week day info
 * return: none
 */
static void get_week_config_info_str(char *value, int *week)
{
	int i = 0;
	int day_index = 0;
	int first_flag = 0;
	int left_flag = 0;
	char tmp[20];

	memset(tmp,0,20);
    memset(value,0,20);
	for(i = 1; i< 8; ++i){
		day_index = i % 7;
		if(1 == week[day_index]){
			if(0 == first_flag){
				snprintf(value,20,"%1d",i);
				memcpy(tmp,value,20);
				left_flag = 1;
				first_flag = 1;
			}
			else{
				if(left_flag){
					if((i < 7) && (1 == week[(i +1) % 7]))
						continue;
					snprintf(value,20,"%s-%1d",tmp,i);
					memcpy(tmp,value,20);
					left_flag = 0;
				}else
				{
					snprintf(value,20,"%s,%1d",tmp,i);
					memcpy(tmp,value,20);
					left_flag = 1;
				}
			}

		}
		else{
			left_flag = 0;
		}
	}
	ak_print_normal_ex("%s\n",value);

}

/** ak_config_get_sys_video: get system video config, title: video
 * @void
 * return: video config info pointer
 */
struct video_config* ak_config_get_sys_video(void)
{
    return config.video;
}

/**
 * ak_config_set_sys_video: set video config, title: video
 * @video[IN]: video config
 * return: void
 */
void ak_config_set_sys_video(struct video_config *video)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    sprintf(value, "%d", video->min_qp);
    ak_ini_set_item_value(config.handle, "video", "min_qp", value);
    sprintf(value, "%d", video->max_qp);
    ak_ini_set_item_value(config.handle, "video", "max_qp", value);
    sprintf(value, "%d", video->v720p_fps);
    ak_ini_set_item_value(config.handle, "video", "v720p_fps", value);
    sprintf(value, "%d", video->v720p_min_kbps);
    ak_ini_set_item_value(config.handle, "video", "v720p_min_kbps", value);
    sprintf(value, "%d", video->v720p_max_kbps);
    ak_ini_set_item_value(config.handle, "video", "v720p_max_kbps", value);

    sprintf(value, "%d", video->vga_fps);
    ak_ini_set_item_value(config.handle, "video", "vga_fps", value);
    sprintf(value, "%d", video->vga_min_kbps);
    ak_ini_set_item_value(config.handle, "video", "vga_min_kbps", value);
    sprintf(value, "%d", video->vga_max_kbps);
    ak_ini_set_item_value(config.handle, "video", "vga_max_kbps", value);

    sprintf(value, "%d", video->gop_len);
    ak_ini_set_item_value(config.handle, "video", "gop_len", value);
    sprintf(value, "%d", video->quality);
    ak_ini_set_item_value(config.handle, "video", "quality", value);
    sprintf(value, "%d", video->pic_ch);
    ak_ini_set_item_value(config.handle, "video", "pic_ch", value);
    sprintf(value, "%d", video->video_mode);
    ak_ini_set_item_value(config.handle, "video", "video_mode", value);
    sprintf(value, "%d", video->method);
    ak_ini_set_item_value(config.handle, "video", "method", value);
}

/**
 * ak_config_get_record: get record config, title: record
 * return: record config struct pointer
 */
struct video_record_config *ak_config_get_record(void)
{
    return config.record;
}

/**
 * ak_config_get_record: get record config, title: record
 * return: record config struct pointer
 */
void *ak_config_set_record_time(int time_ms)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

	sprintf(value, "%d", time_ms);
	ak_ini_set_item_value(config.handle, "record", "record_time", value);
	ak_ini_flush_data(config.handle);
	return NULL;
}
void *ak_config_set_sys_wifi_ap(char *name)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

	sprintf(value,"%s", name);
	ak_ini_set_item_value(config.handle, "softap", "s_ssid", value);
	ak_ini_flush_data(config.handle);
	
	return NULL;
}

static void init_video_param(struct video_config *video)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

	/* get all item values of video title */
    ak_ini_get_item_value(config.handle, "video", "min_qp", value);
    video->min_qp = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "max_qp", value);
    video->max_qp = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "v720p_fps", value);
    video->v720p_fps = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "v720p_min_kbps", value);
    video->v720p_min_kbps = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "v720p_max_kbps", value);
    video->v720p_max_kbps = atoi(value);

    ak_ini_get_item_value(config.handle, "video", "vga_fps", value);
    video->vga_fps = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "vga_min_kbps", value);
    video->vga_min_kbps = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "vga_max_kbps", value);
    video->vga_max_kbps = atoi(value);

    ak_ini_get_item_value(config.handle, "video", "gop_len", value);
    video->gop_len = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "quality", value);
    video->quality = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "pic_ch", value);
    video->pic_ch = atoi(value);
    ak_ini_get_item_value(config.handle, "video", "video_mode", value);
    video->video_mode = atoi(value);

	/* add a new item, if old ini haven't this item, add it */
	if (ak_ini_get_item_value(config.handle, "video", "method", value)) {
		sprintf(value, "%d", 0);
		ak_ini_set_item_value(config.handle, "video", "method", value);
		ak_ini_flush_data(config.handle);
	}
	video->method = atoi(value);
}

static void init_sys_alarm(struct sys_alarm_config *alarm)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    ak_ini_get_item_value(config.handle, "alarm", "md_set", value);
    alarm->md_set = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "md_level_1", value);
    alarm->md_level_1 = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "md_level_2", value);
    alarm->md_level_2 = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "md_level_3", value);
    alarm->md_level_3 = atoi(value);

    ak_ini_get_item_value(config.handle, "alarm", "sd_set", value);
    alarm->sd_set = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "sd_level_1", value);
    alarm->sd_level_1 = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "sd_level_2", value);
    alarm->sd_level_2 = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "sd_level_3", value);
    alarm->sd_level_3 = atoi(value);

    ak_ini_get_item_value(config.handle, "alarm", "i2o_detection", value);
    alarm->i2o_detection = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "smoke_detection", value);
    alarm->smoke_detection = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "shadow_detection", value);
    alarm->shadow_detection = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "other_detection", value);
    alarm->other_detection = atoi(value);

    ak_ini_get_item_value(config.handle, "alarm", "alarm_send_type", value);
    alarm->send_type = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "alarm_interval_time", value);
    alarm->interval_time = atoi(value);
    ak_ini_get_item_value(config.handle, "alarm", "alarm_send_msg_time", value);
    alarm->send_msg_time = atoi(value);
}

static void init_sys_net(struct sys_net_config *net)
{
    char value[CONFIG_VALUE_BUF_SIZE] = {0};

    ak_ini_get_item_value(config.handle, "ethernet", "dhcp", value);
    net->dhcp = atoi(value);
    ak_ini_get_item_value(config.handle, "ethernet", "ipaddr", value);
    strcpy(net->ipaddr, value);
    ak_ini_get_item_value(config.handle, "ethernet", "netmask", value);
    strcpy(net->netmask, value);
    ak_ini_get_item_value(config.handle, "ethernet", "gateway", value);
    strcpy(net->gateway, value);
    ak_ini_get_item_value(config.handle, "ethernet", "firstdns", value);
    strcpy(net->firstdns, value);
    ak_ini_get_item_value(config.handle, "ethernet", "backdns", value);
    strcpy(net->backdns, value);
}

static void get_net_info(void)
{
	/* get iface name */
	char iface[10] = {0};
	char ip[16] = {0}, netmask[16] = {0}, route[16] = {0},
		 mdns[16] = {0}, sdns[16] = {0};

	/* interface, use for get specifically interface's netinfo */
	if (ak_net_get_cur_iface(iface)) {
		ak_print_error_ex("no working net face\n");
		return;
	}

	/* ip */
	if (!ak_net_get_ip(iface, ip)) {
		memset(config.net->ipaddr, 0, sizeof(config.net->ipaddr));
		strcpy(config.net->ipaddr, ip);
	}

	/* netmask */
	if (!ak_net_get_netmask(iface, netmask)) {
		memset(config.net->netmask, 0, sizeof(config.net->netmask));
		strcpy(config.net->netmask, netmask);
	}

	/* route */
	if (!ak_net_get_route(iface, route)) {
		memset(config.net->gateway, 0, sizeof(config.net->gateway));
		strcpy(config.net->gateway, route);
	}

	/* first dns */
	if (ak_net_get_dns(0, mdns)) {
	    strcpy(mdns, route);
	} else {
	    memset(config.net->firstdns, 0, sizeof(config.net->firstdns));
		strcpy(config.net->firstdns, mdns);
	}

	/* back dns */
	if (ak_net_get_dns(1, sdns)) {
	    strcpy(sdns, mdns);
	} else {
	    memset(config.net->backdns, 0, sizeof(config.net->backdns));
		strcpy(config.net->backdns, sdns);
	}
}

/**
 * ak_config_get_sys_net: get system network config
 * return: network config struct pointer
 */
struct sys_net_config* ak_config_get_sys_net(void)
{
    if(config.net->dhcp == 1){
        get_net_info();
    }

    return config.net;
}

/**
 * ak_config_set_sys_net: set system network config
 * @net[IN]: network config
 * return: void
 */
void ak_config_set_sys_net(struct sys_net_config *net)
{
    char value[CONFIG_VALUE_BUF_SIZE] = {0};

	memcpy(config.net, net, sizeof(struct sys_net_config));
    sprintf(value,"%d", config.net->dhcp);
    ak_ini_set_item_value(config.handle, "ethernet", "dhcp", value);
    sprintf(value,"%s", config.net->ipaddr);
    ak_ini_set_item_value(config.handle, "ethernet", "ipaddr", value);
    sprintf(value,"%s", config.net->netmask);
    ak_ini_set_item_value(config.handle, "ethernet", "netmask", value);
    sprintf(value,"%s", config.net->gateway);
    ak_ini_set_item_value(config.handle, "ethernet", "gateway", value);
    sprintf(value,"%s", config.net->firstdns);
    ak_ini_set_item_value(config.handle, "ethernet", "firstdns", value);
    sprintf(value,"%s", config.net->backdns);
    ak_ini_set_item_value(config.handle, "ethernet", "backdns", value);
}

static void init_sys_wifi(struct sys_wifi_config * net)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    ak_ini_get_item_value(config.handle, "wireless", "ssid", value);
    strcpy(net->ssid, value);
    ak_ini_get_item_value(config.handle, "wireless", "mode", value);
    strcpy(net->mode, value);
    ak_ini_get_item_value(config.handle, "wireless", "password", value);
    strcpy(net->passwd, value);
    ak_ini_get_item_value(config.handle, "wireless", "security", value);
	if(strstr(value, "WPA")){
		net->enc_type = WIFI_ENCTYPE_WPA2_TKIP;
	}else if(strstr(value, "WEP")){
		net->enc_type = WIFI_ENCTYPE_WEP;
	}else{
		net->enc_type = WIFI_ENCTYPE_NONE;
	}

	ak_ini_get_item_value(config.handle, "softap", "s_ssid", value);
	strcpy(net->ap_ssid, value);
	ak_ini_get_item_value(config.handle, "softap", "s_password", value);
	strcpy(net->ap_pswd, value);
}

/**
 * ak_config_get_sys_wifi: get system wifi config
 * return: wifi config struct pointer
 */
struct sys_wifi_config* ak_config_get_sys_wifi(void)
{
    return config.wifi;
}

/**
 * ak_config_set_sys_wifi: set system wifi config
 * @wifi[IN]: wifi config
 * @save_ssid_f[IN]: save ssid or not
 * return: void
 */
void ak_config_set_sys_wifi(struct sys_wifi_config *wifi, int save_ssid_f)
{
    char value[CONFIG_VALUE_BUF_SIZE] = {0};

    memcpy(config.wifi, wifi, sizeof(struct sys_wifi_config));
	/*
	 * if not verify,the ssid save to /tmp/wireless/;
	 * otherwise, save to configure
	 */
	if(save_ssid_f){
    	sprintf(value,"%s", config.wifi->ssid);
    	ak_ini_set_item_value(config.handle, "wireless", "ssid", value);
	}
    sprintf(value,"%s", config.wifi->passwd);
    ak_ini_set_item_value(config.handle, "wireless", "password", value);

	if (wifi->ap_ssid) {
		sprintf(value,"%s", config.wifi->ap_ssid);
		ak_ini_set_item_value(config.handle, "softap", "s_ssid", value);
	}
	if (wifi->ap_pswd) {
		sprintf(value,"%s", config.wifi->ap_pswd);
		ak_ini_set_item_value(config.handle, "softap", "s_password", value);
	}
	ak_ini_flush_data(config.handle);
}

static void init_sys_onvif(struct sys_onvif_config * onvif)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    ak_ini_get_item_value(config.handle, "onvif", "main_fps", value);
    onvif->main_fps = atoi(value);
    ak_ini_get_item_value(config.handle, "onvif", "main_kbps", value);
    onvif->main_kbps = atoi(value);
    ak_ini_get_item_value(config.handle, "onvif", "main_quality", value);
    onvif->main_quality = atoi(value);
    ak_ini_get_item_value(config.handle, "onvif", "sub_fps", value);
    onvif->sub_fps = atoi(value);
    ak_ini_get_item_value(config.handle, "onvif", "sub_kbps", value);
    onvif->sub_kbps = atoi(value);
    ak_ini_get_item_value(config.handle, "onvif", "sub_quality", value);
    onvif->sub_quality = atoi(value);
}

/**
 * ak_config_get_sys_onvif: get onvif config
 * return: onvif config struct pointer
 */
struct sys_onvif_config* ak_config_get_sys_onvif(void)
{
    return config.onvif;
}

/**
 * ak_config_set_sys_onvif: set onvif config
 * @onvif[IN]: onvif config
 * return: void
 */
void ak_config_set_sys_onvif(struct sys_onvif_config *onvif)
{
    char value[CONFIG_VALUE_BUF_SIZE] = {0};

	memcpy(config.onvif, onvif, sizeof(struct sys_onvif_config));
    sprintf(value, "%d", config.onvif->main_fps);
    ak_ini_set_item_value(config.handle, "onvif", "main_fps", value);
    sprintf(value, "%d", config.onvif->main_kbps);
    ak_ini_set_item_value(config.handle, "onvif", "main_kbps", value);
    sprintf(value, "%d", config.onvif->main_quality);
    ak_ini_set_item_value(config.handle, "onvif", "main_quality", value);
    sprintf(value, "%d", config.onvif->sub_fps);
    ak_ini_set_item_value(config.handle, "onvif", "sub_fps", value);
    sprintf(value, "%d", config.onvif->sub_kbps);
    ak_ini_set_item_value(config.handle, "onvif", "sub_kbps", value);
    sprintf(value, "%d", config.onvif->sub_quality);
    ak_ini_set_item_value(config.handle, "onvif", "sub_quality", value);
}

static void init_sys_cloud_config(struct sys_cloud_config *cloud)
{
    char value[CONFIG_VALUE_BUF_SIZE] = {0};

    ak_ini_get_item_value(config.handle, "cloud", "onvif", value);
    cloud->onvif = atoi(value);

	ak_ini_get_item_value(config.handle, "cloud", "dana", value);
    cloud->dana = atoi(value);

    ak_ini_get_item_value(config.handle, "cloud", "rtsp", value);
    cloud->rtsp = atoi(value);

    ak_ini_get_item_value(config.handle, "cloud", "tencent", value);
    cloud->tencent= atoi(value);
}

/**
 * ak_config_get_sys_cloud: get system cloud config
 * return: cloud config struct pointer
 */
struct sys_cloud_config* ak_config_get_sys_cloud(void)
{
    return config.cloud;
}

/**
 * ak_config_get_sys_alarm: get system alarm config
 * return: system alarm config struct pointer
 */
struct sys_alarm_config* ak_config_get_sys_alarm(void)
{
    return config.alarm;
}

/**
 * ak_config_set_sys_alarm: set system alarm config
 * return: void
 */
void ak_config_set_sys_alarm(void)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

	sprintf(value,"%d", config.alarm->md_set);
    ak_ini_set_item_value(config.handle, "alarm", "md_set", value);
    sprintf(value,"%d", config.alarm->md_level_1 );
    ak_ini_set_item_value(config.handle, "alarm", "md_level_1", value);
    sprintf(value,"%d", config.alarm->md_level_2 );
    ak_ini_set_item_value(config.handle, "alarm", "md_level_2", value);
    sprintf(value,"%d", config.alarm->md_level_3 );
    ak_ini_set_item_value(config.handle, "alarm", "md_level_3", value);

    sprintf(value,"%d", config.alarm->sd_set);
    ak_ini_set_item_value(config.handle, "alarm", "sd_set", value);
    sprintf(value,"%d", config.alarm->sd_level_1 );
    ak_ini_set_item_value(config.handle, "alarm", "sd_level_1", value);
    sprintf(value,"%d", config.alarm->sd_level_2 );
    ak_ini_set_item_value(config.handle, "alarm", "sd_level_2", value);
    sprintf(value,"%d", config.alarm->sd_level_3 );
    ak_ini_set_item_value(config.handle, "alarm", "sd_level_3", value);

    sprintf(value,"%d", config.alarm->i2o_detection );
    ak_ini_set_item_value(config.handle, "alarm", "i2o_detection", value);
    sprintf(value,"%d", config.alarm->shadow_detection );
    ak_ini_set_item_value(config.handle, "alarm", "shadow_detection", value);
    sprintf(value,"%d", config.alarm->shadow_detection );
    ak_ini_set_item_value(config.handle, "alarm", "shadow_detection", value);
    sprintf(value,"%d", config.alarm->other_detection );
    ak_ini_set_item_value(config.handle, "alarm", "other_detection", value);
    sprintf(value,"%d", config.alarm->send_type );
    ak_ini_set_item_value(config.handle, "alarm", "alarm_send_type", value);
}

static void init_record(struct video_record_config *record)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

	ak_ini_get_item_value(config.handle, "record", "record_server", value);
    record->server_flag = atoi(value);
    ak_ini_get_item_value(config.handle, "record", "record_mode", value);
	record->record_mode = atoi(value);
	ak_ini_get_item_value(config.handle, "record", "record_time", value);
    record->duration = atoi(value);
    ak_ini_get_item_value(config.handle, "record", "record_path", value);
    strcpy(record->path, value);

    ak_ini_get_item_value(config.handle, "record", "sample_rate", value);
    record->sample_rate = atoi(value);
    ak_ini_get_item_value(config.handle, "record", "save_cyc_flag", value);
    record->save_cyc_flag = atoi(value);
    ak_ini_get_item_value(config.handle, "record", "save_file_fps", value);
    record->save_file_fps = atoi(value);
    ak_ini_get_item_value(config.handle, "record", "save_file_kbps", value);
    record->save_file_kbps = atoi(value);
   	ak_ini_get_item_value(config.handle, "record", "min_file_fps", value);
    record->min_file_fps = atoi(value);

    int i = 0;
    char tmp[50] = {0};

    for (i=0; i<MAX_RECORD_PLAN_NUM; ++i) {
    	sprintf(tmp, "plan%d_week_active", (i+1));
    	ak_ini_get_item_value(config.handle, "record", tmp, value);
	    memset(record->plan[i].week_enalbe, 0x00, sizeof(record->plan[i].week_enalbe));
	    save_week_config_info(value, record->plan[i].week_enalbe);

    	sprintf(tmp, "plan%d_run", (i+1));
	    ak_ini_get_item_value(config.handle, "record", tmp, value);
	    record->plan[i].active = atoi(value);

	    sprintf(tmp, "plan%d_start_time", (i+1));
	    ak_ini_get_item_value(config.handle, "record", tmp, value);
	    record->plan[i].start_time = day_clock_to_seconds(value);

	    sprintf(tmp, "plan%d_end_time", (i+1));
	    ak_ini_get_item_value(config.handle, "record", tmp, value);
	    record->plan[i].end_time = day_clock_to_seconds(value);
    }

    ak_ini_get_item_value(config.handle, "record", "alarm_pre_time", value);
    record->alarm_pre_time = atoi(value);
    ak_ini_get_item_value(config.handle, "record", "alarm_stop_time", value);
    record->alarm_stop_time = atoi(value);
}

/**
 * ak_config_set_record_plan: set record config
 * @record[IN]: record config
 * return: void
 */
void ak_config_set_record_plan(struct video_record_config *record)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    sprintf(value, "%d", record->plan[0].active);
    ak_ini_set_item_value(config.handle, "record", "plan1_run", value);
    day_second_to_string(value, record->plan[0].start_time);
    ak_ini_set_item_value(config.handle, "record", "plan1_start_time", value);
    day_second_to_string(value, record->plan[0].end_time);
    ak_ini_set_item_value(config.handle, "record", "plan1_end_time", value);

    get_week_config_info_str(value,record->plan[0].week_enalbe);
    ak_ini_set_item_value(config.handle, "record", "plan1_week_active", value);
    sprintf(value, "%d", record->plan[1].active);
    ak_ini_set_item_value(config.handle, "record", "plan2_run", value);
    day_second_to_string(value, record->plan[1].start_time);
    ak_ini_set_item_value(config.handle, "record", "plan2_start_time", value);
    day_second_to_string(value, record->plan[1].end_time);
    ak_ini_set_item_value(config.handle, "record", "plan2_end_time", value);
    get_week_config_info_str(value,record->plan[1].week_enalbe);
    ak_ini_set_item_value(config.handle, "record", "plan2_week_active", value);
    sprintf(value, "%d", record->plan[2].active);
    ak_ini_set_item_value(config.handle, "record", "plan3_run", value);
    day_second_to_string(value, record->plan[2].start_time);
    ak_ini_set_item_value(config.handle, "record", "plan3_start_time", value);
    day_second_to_string(value, record->plan[2].end_time);
    ak_ini_set_item_value(config.handle, "record", "plan3_end_time", value);
    get_week_config_info_str(value,record->plan[2].week_enalbe);
    ak_ini_set_item_value(config.handle, "record", "plan3_week_active", value);
}

static void init_camera_config(struct camera_disp_config * camera)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    ak_ini_get_item_value(config.handle, "camera", "main_width", value);
    camera->main_width = atoi(value);
    ak_ini_get_item_value(config.handle, "camera", "main_height", value);
    camera->main_height = atoi(value);
    ak_ini_get_item_value(config.handle, "camera", "sub_width", value);
    camera->sub_width = atoi(value);
    ak_ini_get_item_value(config.handle, "camera", "sub_height", value);
    camera->sub_height = atoi(value);

    ak_ini_get_item_value(config.handle, "camera", "osd_position", value);
    camera->osd_position = atoi(value);
    ak_ini_get_item_value(config.handle, "camera", "osd_switch", value);
    camera->osd_switch = atoi(value);

    ak_ini_get_item_value(config.handle, "camera", "osd_name", value);
    strcpy(camera->osd_name, value);
    ak_ini_get_item_value(config.handle, "camera", "osd_rate", value);
    camera->osd_rate = atoi(value);

    ak_ini_get_item_value(config.handle, "camera", "time_switch", value);
    camera->time_switch = atoi(value);
    ak_ini_get_item_value(config.handle, "camera", "date_format", value);
    camera->date_format = atoi(value);
    ak_ini_get_item_value(config.handle, "camera", "hour_format", value);
    camera->hour_format = atoi(value);
    ak_ini_get_item_value(config.handle, "camera", "week_format", value);
    camera->week_format = atoi(value);
   	ak_ini_get_item_value(config.handle, "camera", "day_ctrl", value);
    camera->day_ctrl = atoi(value);
}

/**
 * ak_config_set_camera_info: set camera config
 * @camera[IN]: camera config
 * return: void
 */
void ak_config_set_camera_info(struct camera_disp_config *camera)
{
	ak_print_debug("osd_name len : %d\n", strlen(camera->osd_name));

	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    sprintf(value, "%d", camera->main_width);
    ak_ini_set_item_value(config.handle, "camera", "main_width", value);
    sprintf(value, "%d", camera->main_height);
    ak_ini_set_item_value(config.handle, "camera", "main_height", value);
    sprintf(value, "%d", camera->sub_width);
    ak_ini_set_item_value(config.handle, "camera", "sub_width", value);
    sprintf(value, "%d", camera->sub_height);
    ak_ini_set_item_value(config.handle, "camera", "sub_height", value);
    sprintf(value, "%d", camera->osd_position);
    ak_ini_set_item_value(config.handle, "camera", "osd_position", value);
    sprintf(value, "%d", camera->osd_switch);
    ak_ini_set_item_value(config.handle, "camera", "osd_switch", value);
    sprintf(value, "%s", camera->osd_name);
    ak_ini_set_item_value(config.handle, "camera", "osd_name", value);
    sprintf(value, "%d", camera->time_switch);
    ak_ini_set_item_value(config.handle, "camera", "time_switch", value);
    sprintf(value, "%d", camera->date_format);
    ak_ini_set_item_value(config.handle, "camera", "date_format", value);
    sprintf(value, "%d", camera->hour_format);
    ak_ini_set_item_value(config.handle, "camera", "hour_format", value);
    sprintf(value, "%d", camera->week_format);
    ak_ini_set_item_value(config.handle, "camera", "week_format", value);
    sprintf(value, "%d", camera->day_ctrl);
    ak_ini_set_item_value(config.handle, "camera", "day_ctrl", value);
}

/**
 * ak_config_get_camera_info: get camera config
 * return: camera config struct pointer
 */
struct camera_disp_config* ak_config_get_camera_info(void)
{
    return config.camera;
}

/**
 * ak_config_set_record_plan_by_net: set record plan config
 * @plan[IN]: record plan config
 * return: void
 */
void ak_config_set_record_plan_by_net(struct record_plan_config *plan)
{
    int index = 0;

    if(plan->active){
        for(index = 0; index < MAX_RECORD_PLAN_NUM; index ++){
            if(config.record->plan[index].active == 0){
                break;
            }
        }
        if(index != MAX_RECORD_PLAN_NUM){
            memcpy(&config.record->plan[index], plan,
            	sizeof(struct record_plan_config));
        }
    }else{
        for(index = 0; index < MAX_RECORD_PLAN_NUM; index ++){
            if((config.record->plan[index].start_time == plan->start_time)
            	&& (config.record->plan[index].end_time == plan->end_time)){
            	int i = 0;
            	for(i=0; i<DAY_PER_WEEK; ++i){
            		if(config.record->plan[index].week_enalbe[i]
            			!= plan->week_enalbe[i]){
            			break;
            		}
            	}
            	if(i >= DAY_PER_WEEK){
            		config.record->plan[index].active = 0;
                	break;
            	}
            }
        }
    }

    ak_config_set_record_plan(config.record);
}

/**
 * ak_config_set_ptz: set ptz control config
 * @con[IN]: ptz control config
 * @para1[IN]: ptz control index
 * return: void
 */
void ak_config_set_ptz(void *con, int para1)
{
	struct ptz_pos * ptz_contrl = (struct ptz_pos *)con;
	char *title = "ptz";
	char name[50];
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    sprintf(name, "p%dL", para1);
    sprintf(value, "%d", ptz_contrl[para1-1].left);
    ak_ini_set_item_value(config.handle, title, name, value);
	sprintf(name, "p%dU", para1);
    sprintf(value, "%d", ptz_contrl[para1-1].up);
    ak_ini_set_item_value(config.handle, title, name, value);
}

/**
 * ak_config_get_ptz: get ptz control config
 * @con[OUT]: ptz control config
 * @para1[IN]: ptz control index
 * return: void
 */
void ak_config_get_ptz(void *con, int para1)
{
	struct ptz_pos * ptz_contrl = (struct ptz_pos *)con;

	char *title = "ptz";
	char name[50];
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    sprintf(name, "p%dL", para1);
    ak_ini_get_item_value(config.handle, title, name, value);
	ptz_contrl[para1-1].left = atoi(value);
    sprintf(name, "p%dU", para1);
    ak_ini_get_item_value(config.handle, title, name, value);
    ptz_contrl[para1-1].up = atoi(value);
}

/**
 * ak_config_set_ptz_unhit: set first ptz control config
 * @con[IN]: ptz control config
 * return: void
 */
void ak_config_set_ptz_unhit(void *con)
{
    struct ptz_pos * ptz_contrl = (struct ptz_pos *)con;
	char *title = "ptz";
    char value[CONFIG_VALUE_BUF_SIZE] = {0};

	if (access(CONFIG_PTZ_UNHIT_NAME, F_OK) != 0) {
		sprintf(value, "echo \"[%s]\" > %s", title, CONFIG_PTZ_UNHIT_NAME);
		system(value);
	}

    sprintf(value, "%d", ptz_contrl[0].left);
    ak_ini_set_item_value(config.handle, title, "hitL", value);
    sprintf(value, "%d", ptz_contrl[0].up);
    ak_ini_set_item_value(config.handle, title, "hitU", value);
}

/**
 * ak_config_get_ptz_unhit: get first ptz control config
 * @con[OUT]: ptz control config
 * return: void
 */
void ak_config_get_ptz_unhit(void *con)
{
	struct ptz_pos * ptz_contrl = (struct ptz_pos *)con;

	char *title = "ptz";
    char value[CONFIG_VALUE_BUF_SIZE] = {0};

	if (access(CONFIG_PTZ_UNHIT_NAME, F_OK) != 0) {
		sprintf(value, "echo \"[%s]\" > %s", title, CONFIG_PTZ_UNHIT_NAME);
		system(value);
	}

    ak_ini_get_item_value(config.handle, title, "hitL", value);
	ptz_contrl[0].left = atoi(value);
    ak_ini_get_item_value(config.handle, title, "hitU", value);
    ptz_contrl[0].up = atoi(value);
}

static void init_system_user(struct sys_user_config *user)
{
	char value[CONFIG_VALUE_BUF_SIZE] = {0};

    ak_ini_get_item_value(config.handle, "global", "user", value);
    strcpy(user->name, value);
    ak_ini_get_item_value(config.handle, "global", "secret", value);
    strcpy(user->secret, value);
    ak_ini_get_item_value(config.handle, "global", "dev_name", value);
	strcpy(user->dev_name, value);
	ak_ini_get_item_value(config.handle, "global", "soft_version", value);
	user->soft_version = atoi(value);
	memset(user->uid_name,0,100);
	if(0 == ak_ini_get_item_value(config.handle, "global", "uid_name", value)){
		strcpy(user->uid_name, value);
	}
}

/**
 * ak_config_get_system_user: get system user info config
 * return: user info config struct pointer
 */
struct sys_user_config* ak_config_get_system_user(void)
{
	return config.user;
}

/**
 * ak_config_set_system_user: set user info config
 * @user_info[IN]: user info config
 * return: void
 */
void ak_config_set_system_user(struct sys_user_config *user)
{
	char *title = "global";
    char value[100];

    sprintf(value, "%s", user->name);
	ak_ini_set_item_value(config.handle, title, "user", value);
    sprintf(value, "%s", user->secret);
	ak_ini_set_item_value(config.handle, title, "secret", value);
    sprintf(value, "%s", user->dev_name);
	ak_ini_set_item_value(config.handle, title, "dev_name", value);
    sprintf(value, "%u", user->soft_version);
	ak_ini_set_item_value(config.handle, title, "soft_version", value);
}

/**
 * ak_config_init_ini: init ini module
 * return: void
 */
void ak_config_init_ini(void)
{
	config.handle = ak_ini_init(CONFIG_ANYKA_FILE_NAME);
    if(NULL == config.handle) {
        ak_print_normal_ex("open config file failed, create it.\n");
		system("cp /usr/local/factory_cfg.ini /etc/jffs2/anyka_cfg.ini");
		config.handle = ak_ini_init(CONFIG_ANYKA_FILE_NAME);
		if(NULL == config.handle) {
			ak_print_normal_ex("open config file failed & create failed\n");
			return;
		}
    } else {
		ak_print_normal_ex("anyka config file check ok.\n\n");
	}

    config.video = (struct video_config *)calloc(1,
    	sizeof(struct video_config));
    config.record = (struct video_record_config *)calloc(1,
    	sizeof(struct video_record_config));
    config.alarm = (struct sys_alarm_config *)calloc(1,
    	sizeof(struct sys_alarm_config));
    config.onvif = (struct sys_onvif_config *)calloc(1,
    	sizeof(struct sys_onvif_config));
    config.cloud = (struct sys_cloud_config *)calloc(1,
    	sizeof(struct sys_cloud_config));
    config.net = (struct sys_net_config *)calloc(1,
    	sizeof(struct sys_net_config));
    config.wifi = (struct sys_wifi_config *)calloc(1,
    	sizeof(struct sys_wifi_config));
    config.camera = (struct camera_disp_config *)calloc(1,
    	sizeof(struct camera_disp_config));
    config.user = (struct sys_user_config *)calloc(1,
    	sizeof(struct sys_user_config));

	init_video_param(config.video);
#if CONFIG_DUMP_INFO
	ak_ini_dump_config(config.handle, "ethernet");
#endif
    init_record(config.record);
    init_sys_alarm(config.alarm);
    init_sys_onvif(config.onvif);
    init_sys_cloud_config(config.cloud);
    init_sys_net(config.net);
    init_sys_wifi(config.wifi);
    init_camera_config(config.camera);
    init_system_user(config.user);
}

/**
 * ak_config_release_ini: destroy ini module
 * return: void
 */
void ak_config_release_ini(void)
{
	ak_ini_destroy(config.handle);
}

/**
 * ak_config_flush_data: flush data
 * return: void
 */
void ak_config_flush_data(void)
{
    if(config.handle)
		ak_ini_flush_data(config.handle);
}

/**
 * ak_config_update_ssid:  get wifi ssid  from config file
 * return: 0 -> success; -1 -> fail;
 * notes: wifi ssid configure change by script cmd, we need to
 *          update configure copy in memory.
 *          it is special.
 */
int ak_config_update_ssid(void)
{
	char cmd[128] = {0};
	char *tmp_cfg = "/tmp/tmp_cfg.ini";
	void *cfg_handle = NULL;
	char value[CONFIG_VALUE_BUF_SIZE] = {0};
	int retry_count = 0;

	if(NULL == config.handle) {
    	ak_print_error_ex("config file not init.\n");
		return AK_FAILED;
	}
	if(NULL == config.wifi){
		ak_print_error_ex("config.wifi null.\n");
		return AK_FAILED;
	}
	for(retry_count = 0; retry_count < 4; retry_count++) {
		sprintf(cmd, "cp %s %s", CONFIG_ANYKA_FILE_NAME, tmp_cfg);
		if(ak_cmd_exec(cmd, NULL, 0)){
			ak_print_error_ex("%s fail.\n",cmd);
			return AK_FAILED;
		}
		if(access(tmp_cfg, F_OK)){
	        ak_print_notice_ex("%s not ok.\n",tmp_cfg);
			ak_sleep_ms(2000);
			continue;
	    }
		cfg_handle = ak_ini_init(tmp_cfg);
	    if(NULL == cfg_handle) {
	        ak_print_error_ex("ini init %s failed.\n",tmp_cfg);
			return AK_FAILED;
	    }
	    ak_ini_get_item_value(cfg_handle, "wireless", "ssid", value);
	    strcpy(config.wifi->ssid, value);
		if(AK_FAILED == ak_ini_destroy(cfg_handle)){
			ak_print_error_ex("ini_destroy failed.\n");
		}
		sprintf(cmd, "rm -f %s",tmp_cfg);
		ak_cmd_exec(cmd, NULL, 0);
		if(strlen(value) > 0){
			break;
		}
		ak_print_normal_ex("retry count:%d\n",retry_count);
		ak_sleep_ms(2000);
	}
	if(4 == retry_count){
		return AK_FAILED;
	}
	ak_ini_set_item_value(config.handle, "wireless", "ssid", value);
	ak_print_normal_ex("ssid:%s pwd:%s\n",config.wifi->ssid,config.wifi->passwd);

	return AK_SUCCESS;
}
